package com.example.meitu.api.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.meitu.api.common.UserLoginContextHolder;
import com.example.meitu.api.dao.ArticleMapper;
import com.example.meitu.api.domain.Article;
import com.example.meitu.api.domain.Media;
import com.example.meitu.api.dto.ArticleMediaDTO;
import com.example.meitu.api.dto.ArticlesDTO;
import com.example.meitu.api.dto.CompetitorRecommandMediaDTO;
import com.example.meitu.api.dto.RecommandMediaForm;
import com.example.meitu.api.service.ArticleService;
import com.example.meitu.api.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author 蔡超
* @description 针对表【mt_article(媒体文章表)】的数据库操作Service实现
* @createDate 2024-07-03 14:45:51
*/
@Service
@Slf4j
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>
    implements ArticleService{

    @Resource
    private MediaService mediaService;

    @Resource
    private ArticleMapper articleMapper;

    /**
     * 媒体详情页 - 高相关品牌
     * 根据媒体账号id + 发布时间区间， 查询文章表
     * lits 根据 doc_id 去重，并且 publish_time 倒序 Map<DocId,List<Article>>
     * 遍历map 拼接成 ArticlesDTO
     * @param accountId
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public List<ArticlesDTO> getArticles(Integer accountId, Integer startTime, Integer endTime) {

        //注意，过滤有权限的品牌
        List<Integer> permissionBrandIds = UserLoginContextHolder.get().getPermissionBrands();

        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(Article::getAccountId, accountId);
        queryWrapper.eq(Article::getDelFlag, "0");
        queryWrapper.between(Article::getPublishTime, startTime, endTime);
        queryWrapper.in(Article::getBrandId, permissionBrandIds);
        queryWrapper.orderByAsc(Article::getRelatedType);
        queryWrapper.orderByDesc(Article::getPublishTime);
        List<Article> list = list(queryWrapper);

        Map<String,List<Article>> map = list.stream().collect(Collectors.groupingBy(Article::getDocId));
        List<ArticlesDTO> result = new ArrayList<>();
        for (Map.Entry<String, List<Article>> m : map.entrySet()) {
            ArticlesDTO articlesDTO = new ArticlesDTO();
            articlesDTO.setDocId(m.getKey());
            List<Article> accountArticle = m.getValue();
            //从里面取出3个 brands_tiem 最大的
            List<Article> top3 = accountArticle.stream()
                    .sorted(Comparator.comparing(Article::getBrandTimes).reversed()).limit(3).collect(Collectors.toList());
            String brandMame = top3.stream().map(Article::getBrandName).collect(Collectors.joining(","));
            articlesDTO.setBrandName(brandMame);
            articlesDTO.setTitle(top3.get(0).getTitle());
            articlesDTO.setPublishTime(top3.get(0).getPublishTime());
            articlesDTO.setDocUrl(top3.get(0).getDocUrl());
            result.add(articlesDTO);
        }
        return result;
    }

    @Override
    public List<ArticlesDTO> getArticlesBySubUnionId(Integer subUnionId, String platform,Integer startTime, Integer endTime) {

        //注意，过滤有权限的品牌
        List<Integer> permissionBrandIds = UserLoginContextHolder.get().getPermissionBrands();

        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(Article::getSubUnionId, subUnionId);
        if (org.apache.commons.lang3.StringUtils.isNotBlank(platform)){
            queryWrapper.like(Article::getPlatform, platform);
        }
        queryWrapper.eq(Article::getDelFlag, "0");
        queryWrapper.between(Article::getPublishTime, startTime, endTime);
        queryWrapper.in(Article::getBrandId, permissionBrandIds);
        queryWrapper.orderByAsc(Article::getRelatedType);
        queryWrapper.orderByDesc(Article::getPublishTime);
        List<Article> list = list(queryWrapper);

        Map<String,List<Article>> map = list.stream().collect(Collectors.groupingBy(Article::getDocId));
        List<ArticlesDTO> result = new ArrayList<>();
        for (Map.Entry<String, List<Article>> m : map.entrySet()) {
            ArticlesDTO articlesDTO = new ArticlesDTO();
            articlesDTO.setDocId(m.getKey());
            List<Article> accountArticle = m.getValue();
            //从里面取出3个 brands_tiem 最大的
            List<Article> top3 = accountArticle.stream()
                    .sorted(Comparator.comparing(Article::getBrandTimes).reversed()).limit(3).collect(Collectors.toList());
            String brandMame = top3.stream().map(Article::getBrandName).collect(Collectors.joining(","));
            articlesDTO.setBrandName(brandMame);
            articlesDTO.setTitle(top3.get(0).getTitle());
            articlesDTO.setPublishTime(top3.get(0).getPublishTime());
            articlesDTO.setDocUrl(top3.get(0).getDocUrl());
            result.add(articlesDTO);
        }
        return result;
    }

    @Override
    public List<CompetitorRecommandMediaDTO> competitorRecommandMedia(RecommandMediaForm recommandMediaForm) {
        long startTime = System.currentTimeMillis();
        List<CompetitorRecommandMediaDTO> result = new ArrayList<>();

        Integer brandId = recommandMediaForm.getBrandId();
        String platform = recommandMediaForm.getPlatform();
        String meitidalei = recommandMediaForm.getMeitidalei();
        String hangyexifen = recommandMediaForm.getHangyexifen();
        String xifenquanceng = recommandMediaForm.getXifenquanceng();

        boolean searchMedia = StringUtils.isNotBlank(platform) || StringUtils.isNotBlank(meitidalei)
                || StringUtils.isNotBlank(hangyexifen)|| StringUtils.isNotBlank(xifenquanceng);

        List<Integer> mediaIds = new ArrayList<>();

        if (searchMedia) {
            LambdaQueryWrapper<Media> lambdaQueryWrapper = new LambdaQueryWrapper();
            if (StringUtils.isNotBlank(platform)) {
                lambdaQueryWrapper.eq(Media::getPlatform, recommandMediaForm.getPlatform());
            }
            if (StringUtils.isNotBlank(meitidalei)) {
                lambdaQueryWrapper.eq(Media::getMeitidalei, recommandMediaForm.getMeitidalei());
            }
            if (StringUtils.isNotBlank(hangyexifen)) {
                lambdaQueryWrapper.eq(Media::getHangyexifen, recommandMediaForm.getHangyexifen());
            }
            if (StringUtils.isNotBlank(xifenquanceng)) {
                lambdaQueryWrapper.eq(Media::getXifenquanceng, recommandMediaForm.getXifenquanceng());
            }
            List<Media> mediaList = mediaService.list(lambdaQueryWrapper);
            mediaIds = mediaList.stream().map(Media::getId).collect(Collectors.toList());
        }

        log.info("mediaService.list: " + (System.currentTimeMillis() - startTime));

        if (searchMedia && mediaIds.size() == 0) {
            // 没有满足条件的媒体，直接返回空数组
            return result;
        }

        LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(Article::getBrandId, recommandMediaForm.getBrandId());
        lambdaQueryWrapper.eq(Article::getDelFlag, '0');
        if (searchMedia){
            lambdaQueryWrapper.in(Article::getMediaId, mediaIds);
        }
        List<Article> list = list(lambdaQueryWrapper);
        log.info("article.list: " + (System.currentTimeMillis() - startTime));
        //list 转成 Map<Media List<Article>>, List<Article> 再求和正向文章数量  排序，再计算 可能性
        Map<Integer,List<Article>> map = list.stream().collect(Collectors.groupingBy(Article::getMediaId));


        //每个媒体的正向文章数
        Map<Integer,Long> positiveCountMap = list.stream()
                .filter(article -> article.getPositiveFlag().equals(1) || article.getPositiveFlag().equals(2))
                .collect(Collectors.groupingBy(Article::getMediaId, Collectors.counting()));

        //全部媒体
        LambdaQueryWrapper<Media> mediaWrapper = new LambdaQueryWrapper();
        mediaWrapper.eq(Media::getDelFlag,'0');
        List<Media> mediaList = mediaService.list(mediaWrapper);
        Map<Integer,Media> mediaMap = mediaList.stream().collect(Collectors.toMap(Media::getId,a->a,(k1,k2) -> k1));


        //最大的正向文章数量
        long maxPositiveNum = 0;
        Iterator<Map.Entry<Integer,List<Article>>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<Integer, List<Article>> entry = entries.next();
//            log.info("Key = " + entry.getKey() + ", Value = " + entry.getValue());
            Integer mediaId = entry.getKey();
            List<Article> articleList = entry.getValue();
            CompetitorRecommandMediaDTO competitorRecommandMediaDTO = new CompetitorRecommandMediaDTO();
            competitorRecommandMediaDTO.setMediaId(mediaId);
            Media media = mediaMap.get(mediaId);
            if (media == null) {
                log.error("media is null: " + mediaId);
                continue;
            }
            competitorRecommandMediaDTO.setMediaName(media.getMediaName());
            competitorRecommandMediaDTO.setMediacluster(media.getUnionMediaName());
            // 根据媒体id 查询所属集群、媒体属性（）
            String mediaType = String.format("%s|%s|%s", media.getMeitidalei(), media.getHangyexifen(), media.getXifenquanceng());
            competitorRecommandMediaDTO.setMediatype(mediaType);
            long positiveNum = positiveCountMap.get(mediaId) == null ? 0: positiveCountMap.get(mediaId);
            competitorRecommandMediaDTO.setPositiveNum(positiveNum);
            if (positiveNum > maxPositiveNum) {
                maxPositiveNum = positiveNum;
            }
            competitorRecommandMediaDTO.setDocUrl(map.get(mediaId).get(0).getDocUrl());
            competitorRecommandMediaDTO.setTitle(map.get(mediaId).get(0).getTitle());
            result.add(competitorRecommandMediaDTO);
        }

        //从result中获取positiveNum最大的十个10元素
        result.sort(Comparator.comparing(CompetitorRecommandMediaDTO::getPositiveNum).reversed());
        result = result.stream().limit(recommandMediaForm.getNum() == null ? 10: recommandMediaForm.getNum()).collect(Collectors.toList());

        //再循环一下，设置可能性
        BigDecimal max = new BigDecimal("0.9700");
        for (CompetitorRecommandMediaDTO competitorRecommandMediaDTO : result) {
            Long positiveNum = competitorRecommandMediaDTO.getPositiveNum();
            BigDecimal bigDecimal;
            if (positiveNum.equals(maxPositiveNum)){
                bigDecimal = max;
            }else {
                bigDecimal = maxPositiveNum == 0 ? new BigDecimal(0): new BigDecimal(positiveNum).divide(new BigDecimal(maxPositiveNum),4, RoundingMode.HALF_UP);
            }
            competitorRecommandMediaDTO.setProbability(bigDecimal);
        }

        log.info("end: " + (System.currentTimeMillis() - startTime));
        return result;
    }

    public List<CompetitorRecommandMediaDTO> competitorRecommandMedia2(RecommandMediaForm recommandMediaForm) {
        long startTime = System.currentTimeMillis();
        List<CompetitorRecommandMediaDTO> result = new ArrayList<>();

        Integer num = recommandMediaForm.getNum() == null ? 10 : recommandMediaForm.getNum();
        Integer brandId = recommandMediaForm.getBrandId();
        String meitidalei = recommandMediaForm.getMeitidalei();
        String hangyexifen = recommandMediaForm.getHangyexifen();
        String xifenquanceng = recommandMediaForm.getXifenquanceng();
        String meitileixing = recommandMediaForm.getMediaType();

        boolean searchMedia = StringUtils.isNotBlank(meitidalei)
                || StringUtils.isNotBlank(hangyexifen)|| StringUtils.isNotBlank(xifenquanceng)
                || StringUtils.isNotBlank(meitileixing);

        List<Integer> mediaIds = new ArrayList<>();

        if (searchMedia) {
            LambdaQueryWrapper<Media> lambdaQueryWrapper = new LambdaQueryWrapper();
            if (StringUtils.isNotBlank(meitidalei)) {
                lambdaQueryWrapper.eq(Media::getMeitidalei, recommandMediaForm.getMeitidalei());
            }
            if (StringUtils.isNotBlank(hangyexifen)) {
                lambdaQueryWrapper.eq(Media::getHangyexifen, recommandMediaForm.getHangyexifen());
            }
            if (StringUtils.isNotBlank(xifenquanceng)) {
                lambdaQueryWrapper.eq(Media::getXifenquanceng, recommandMediaForm.getXifenquanceng());
            }
            if (StringUtils.isNotBlank(meitileixing)) {
                lambdaQueryWrapper.like(Media::getMeitileixing, recommandMediaForm.getMediaType());
            }
            List<Media> mediaList = mediaService.list(lambdaQueryWrapper);
            mediaIds = mediaList.stream().map(Media::getId).collect(Collectors.toList());
        }

        log.info("mediaService.list: " + (System.currentTimeMillis() - startTime));

        if (searchMedia && mediaIds.size() == 0) {
            // 没有满足条件的媒体，直接返回空数组
            return result;
        }

        //全部媒体
        LambdaQueryWrapper<Media> mediaWrapper = new LambdaQueryWrapper();
        mediaWrapper.eq(Media::getDelFlag,'0');
        List<Media> mediaList = mediaService.list(mediaWrapper);
        Map<Integer,Media> mediaMap = mediaList.stream().collect(Collectors.toMap(Media::getId,a->a,(k1,k2) -> k1));

        //最大的正向文章数量
        long maxPositiveNum = 0;

        //从文章表查询排名前10、20的媒体
        List<ArticleMediaDTO> list = articleMapper.topMedia(brandId,mediaIds,num,recommandMediaForm.getPlatform());
        List<Integer> topMediaIds = list.stream().map(ArticleMediaDTO::getMediaId).collect(Collectors.toList());

        //查询媒体的最新的文章
        Map<Integer,Article> articleMap = getArticleMap(brandId, topMediaIds);

        for (ArticleMediaDTO articleMediaDTO : list) {
            Integer mediaId = articleMediaDTO.getMediaId();
            CompetitorRecommandMediaDTO competitorRecommandMediaDTO = new CompetitorRecommandMediaDTO();
            competitorRecommandMediaDTO.setMediaId(mediaId);
            Media media = mediaMap.get(mediaId);
            if (media == null) {
                log.error("media is null: " + mediaId);
                continue;
            }
            competitorRecommandMediaDTO.setMediaName(media.getMediaName());
            competitorRecommandMediaDTO.setMediacluster(media.getUnionMediaName());
            // 根据媒体id 查询所属集群、媒体属性（）
            String mediaType = String.format("%s|%s|%s", media.getMeitidalei(), media.getHangyexifen(), media.getXifenquanceng());
            competitorRecommandMediaDTO.setMediatype(mediaType);
            long positiveNum = articleMediaDTO.getNum();
            competitorRecommandMediaDTO.setPositiveNum(positiveNum);
            if (positiveNum > maxPositiveNum) {
                maxPositiveNum = positiveNum;
            }
            competitorRecommandMediaDTO.setDocUrl(articleMap.get(mediaId).getDocUrl());
            competitorRecommandMediaDTO.setTitle(articleMap.get(mediaId).getTitle());
            result.add(competitorRecommandMediaDTO);
        }

        //再循环一下，设置可能性
        BigDecimal max = new BigDecimal("0.9700");
        for (CompetitorRecommandMediaDTO competitorRecommandMediaDTO : result) {
            Long positiveNum = competitorRecommandMediaDTO.getPositiveNum();
            BigDecimal bigDecimal;
            if (positiveNum.equals(maxPositiveNum)){
                bigDecimal = max;
            }else {
                bigDecimal = maxPositiveNum == 0 ? new BigDecimal(0): new BigDecimal(positiveNum).divide(new BigDecimal(maxPositiveNum),4, RoundingMode.HALF_UP);
            }
            competitorRecommandMediaDTO.setProbability(bigDecimal);
        }

        return result;
    }

    // 取每个媒体的最新一篇文章,只筛选related_type=0的文章
    private Map<Integer, Article> getArticleMap(Integer brandId, List<Integer> topMediaIds) {
        if (CollectionUtil.isNotEmpty(topMediaIds)) {
            List<Article> articles = articleMapper.topArticle(brandId,topMediaIds);
            return articles.stream().collect(Collectors.toMap(Article::getMediaId, a -> a));
        }
        return null;
    }


}




